﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.Office.Server.Administration;
using Microsoft.Office.Server.Search.Administration;
using Microsoft.SharePoint.Administration;
using TSB.FarmPowerShellWizard.Entities;

namespace TSB.FarmPowerShellWizard.Repository
{
    public class ServiceAppRepository
    {

        private List<string> _supportedServiceTypes = new List<string> { "Search Service Application" }; // 

        public List<ServiceApplication> GetServiceApps()
        {
            var serviceApps = new List<ServiceApplication>();
            var localFarm = SPFarm.Local;
            
            if (localFarm == null)
            {
                return serviceApps;
            }

            foreach (var service in localFarm.Services)
            {
                if (service == null)
                {
                    continue;
                }

                foreach (var srvApplications in service.Applications)
                {
                    serviceApps.Add(new ServiceApplication
                            {
                                Name = srvApplications.Name,
                                Type = srvApplications.TypeName,
                                EnabledScripting = _supportedServiceTypes.Contains(srvApplications.TypeName)
                            });
                }
            }
            
            return serviceApps.Where(srv => srv.EnabledScripting).ToList();
        }

        public string GetServiceAppScript(string serviceAppName)
        {
            var localFarm = SPFarm.Local;

            if (localFarm == null)
            {
                return string.Empty;
            }

            SPServiceApplication thisApp = null;

            foreach (var service in localFarm.Services)
            {
                if (service == null)
                {
                    continue;
                }

                if (thisApp != null)
                {
                    break;
                }

                foreach (var srvApplications in service.Applications)
                {
                    if (srvApplications.Name == serviceAppName)
                    {
                        thisApp = srvApplications;
                    }
                }
            }

            if (thisApp == null)
            {
                return "Not Found";
            }

            switch (thisApp.TypeName)
            {
                case "State Service":
                    return GetScriptForStateService(thisApp);
                case "Managed Metadata Service":
                    return GetScriptForManagedMetadataService(thisApp);
                case "Search Service Application":
                    return GetScriptForSearchService(thisApp);
            }

            return string.Empty;
        }


        string GetScriptForStateService(SPServiceApplication serviceApp)
        {
            if (serviceApp == null)
            {
                return string.Empty;
            }

            var script = new StringBuilder();
            var ssa = serviceApp as StateServiceApplication;
            
            script.AppendFormat(Constants.SCRIPT_TITLE, string.Format("State Service: {0} ", serviceApp.Name));
            script.AppendFormat("\n$serviceAppName = \"{0}\"", serviceApp.Name);

            foreach(var db in ssa.Databases)
            {
                script.AppendFormat("\n$dbName = \"{0}\"", db.Name);
                break;
            }
            
            script.Append("\n$serviceApp = New-SPStateServiceApplication -Name $serviceAppName");
            script.Append("\n\nNew-SPStateServiceDatabase -Name $dbName -ServiceApplication $serviceApp");
            script.Append("\nNew-SPStateServiceApplicationProxy -Name $proxy -ServiceApplication $serviceApp -DefaultProxyGroup");

            return script.ToString();
        }

        string GetScriptForManagedMetadataService(SPServiceApplication serviceApp)
        {
            if (serviceApp == null)
            {
                return string.Empty;
            }
            
            var script = new StringBuilder();
            script.AppendFormat(Constants.SCRIPT_TITLE, string.Format("Managed Metadata Service: {0} ", serviceApp.Name));
            script.AppendFormat("\n$serviceAppName = \"{0}\"", serviceApp.Name);
            
            var mmsRepository = new MMServiceRepository();
            script.AppendFormat("\n$dbName = \"{0}\"", mmsRepository.GetDatabaseName(serviceApp.Name));

            script.Append("\n\n$metadataServiceApp  = New-SPMetadataServiceApplication -Name $serviceAppName -ApplicationPool $appPool -DatabaseName $dbName");
	        script.Append("\n$metadataServiceAppProxy  = New-SPMetadataServiceApplicationProxy -Name $($config.managedMetadataService.name + \" Proxy\") -ServiceApplication $metadataServiceApp -DefaultProxyGroup")
            ;


            return script.ToString();
        }

        string GetScriptForSearchService(SPServiceApplication serviceApp)
        {
            if (serviceApp == null)
            {
                return string.Empty;
            }

            var script = new StringBuilder();
            var ssa = serviceApp as SearchServiceApplication;
            script.AppendFormat(Constants.SCRIPT_TITLE, string.Format("Search Service: {0} ", serviceApp.Name));
            script.AppendFormat("\n$serviceAppName = \"{0}\"", serviceApp.Name);
            script.AppendFormat("\n$adminSearchDB = \"{0}\"", ssa.SearchAdminDatabase.Name);
            script.AppendFormat("\n$appPoolName = \"{0}\"", ssa.ApplicationPool.Name);
            script.AppendFormat("\n$appPoolUsername = \"{0}\"", ssa.ApplicationPool.ProcessAccount.LookupName());
            script.AppendFormat("\n$searchServer = \"{0}\"", ssa.SearchAdminDatabase.Server.Name);

            script.Append("\n\n$searchApp = New-SPEnterpriseSearchServiceApplication -Name $searchAppName -ApplicationPool $appPoolName -DatabaseName $adminSearchDB"
                + "\n$adminSearchInstance = Get-SPEnterpriseSearchServiceInstance | ?{ $_.Server -match $searchServer }"
                + "\n$admin = $searchApp | Get-SPEnterpriseSearchAdministrationComponent"
                + "\n\nif($adminSearchInstance.Status -ne \"Online\") \n    {\n        Write-Host \"Provisioning SharePoint Search Service instance...\" \n        $adminSearchInstance.Provision() \n        Start-Sleep 10 \n    }"
                + "\n$admin | Set-SPEnterpriseSearchAdministrationComponent -SearchServiceInstance $adminSearchInstance"
                + "\n$admin = ($searchApp | Get-SPEnterpriseSearchAdministrationComponent)"
                + "\nWhile (-not $admin.Initialized) \n    {\n        Start-Sleep -Seconds 5 \n        $admin = $searchApp |  Get-SPEnterpriseSearchAdministrationComponent \n    }"
                + "\nStart-SPEnterpriseSearchQueryAndSiteSettingsServiceInstance $searchServer"
                + "\n$initialCrawlTopology = $searchApp | Get-SPEnterpriseSearchCrawlTopology"
                + "\n$initialQueryTopology = $searchApp | Get-SPEnterpriseSearchQueryTopology"
                + "\n$crawlTopology = $searchApp | New-SPEnterpriseSearchCrawlTopology"
                + "\n$crawlDatabase = Get-SPEnterpriseSearchCrawlDatabase -searchApplication $searchApp"
                + "\n$crawlInstance = Get-SPEnterpriseSearchServiceInstance | ?{ $_.Server -match $searchServer }     "
                + "\n$crawlComponent = New-SPEnterpriseSearchCrawlComponent -CrawlTopology $crawlTopology -CrawlDatabase $crawlDatabase -SearchServiceInstance $crawlInstance"
                + "\n$crawlTopology | Set-SPEnterpriseSearchCrawlTopology -Active"
                + "\n$initialCrawlTopology.CancelActivate()"
                + "\nDo \n    {\n        Start-Sleep 5    } While ($initialCrawlTopology.State -ne \"Inactive\")"
                + "\n$queryTopology = $searchApp | New-SPEnterpriseSearchQueryTopology -Partitions 1 "
                + "\n$propertyDatabase = Get-SPEnterpriseSearchPropertyDatabase -SearchApplication $searchApp "
                + "\n$indexPartition = Get-SPEnterpriseSearchIndexPartition -QueryTopology $queryTopology "
                + "\n$indexPartition | Set-SPEnterpriseSearchIndexPartition -PropertyDatabase $propertyDatabase "
                + "\n$queryInstance = Get-SPEnterpriseSearchServiceInstance  | ?{ $_.Server -match $searchServer }"
                + "\n$queryComponent = New-SPEnterpriseSearchQueryComponent -QueryTopology $queryTopology -IndexPartition $indexPartition -SearchServiceInstance $queryInstance "
                + "\n$QueryTopology | Set-SPEnterpriseSearchQueryTopology -Active"
                + "\nDo\n    {\n        Start-Sleep 5\n     } While ($initialQueryTopology.State -ne \"Inactive\")"
                + "\n$initialCrawlTopology | Remove-SPEnterpriseSearchCrawlTopology -Confirm:$false "
                + "\n$initialQueryTopology | Remove-SPEnterpriseSearchQueryTopology -Confirm:$false "
                + "\n$searchProxy = New-SPEnterpriseSearchServiceApplicationProxy -Name $serviceAppName -SearchApplication $searchApp" 
                );

            

            return script.ToString();
        }
        
    }

}
